#include <QDebug>
#include <QRegExp>

#include "defines.h"
#include "symbiandefines.h"
#include "symbianstatusupdater.h"

#define PROGRESS_MAX 1000

SymbianStatusUpdater::SymbianStatusUpdater(SymbianQtProjectGenerator & generator,
                                           QObject                   * parent)
    : IStatusUpdater(parent),
      m_generator(generator)
{
    // Connect generator messages
    connect(&m_generator,
            SIGNAL(started(GeneratorTarget)),
            this,
            SLOT(start(GeneratorTarget)));
    connect(&m_generator,
            SIGNAL(finished(int)),
            this,
            SLOT(stop()));
    connect(&(m_generator.outputView()),
            SIGNAL(message(QString)),
            this,
            SLOT(increase(QString)));

    // Some defaults if others are not provided
    m_phasesInAction = 5;
    m_maximumValue = PROGRESS_MAX;
    m_lastLogCounter = 0;

    // Reset values that can be changed outside
    reset();
}

SymbianStatusUpdater::~SymbianStatusUpdater()
{
    ;
}


void SymbianStatusUpdater::updateGeneratorStatus(bool manualTrigger)
{
    // If progress is indefinite, we're doing some time consuming
    // task with indefinite progress, so do not update the status.
    if (m_indefinite)
        return;

    GeneratorPhase phase = m_generator.getCurrentPhase();

    if (phase == ENDED_SUCCESSFULLY || phase == ENDED_WITH_ERRORS)
    {
        m_currentValue = m_maximumValue;
        m_statusText = m_generator.getStatusText();
        emit updated();
        emit finished(phase == ENDED_SUCCESSFULLY);
    }
    else if (!manualTrigger)
    {
        // Progressbar steps in phase
        int phaseStep = m_maximumValue / m_phasesInAction;

        // Progressbar steps in one message. Phases have very different amount of messages,
        // so we'll calculate an approximation for this.
        int messageStep = phaseStep / phaseLength(phase);
        int currentValue = m_currentValue;
        int nextPhaseStart = (currentValue / phaseStep + 1) * phaseStep;

        if (phase != m_lastPhase)
        {
            // Set the progressbar to the beginning of the next step
            m_statusText = m_generator.getStatusText();
            m_currentValue = nextPhaseStart;
            emit updated();
        }
        else
        {
            // Update at every step, but only up to the next phase's start
            if ((currentValue + messageStep) < nextPhaseStart)
            {
                m_currentValue = currentValue + messageStep;
                emit updated();
            }
        }
    }

    m_lastPhase = phase;
}


void SymbianStatusUpdater::setIndefiniteProgress(bool indefinite)
{
    m_indefinite = indefinite;
}


void SymbianStatusUpdater::setPhases(int phases)
{
    m_phasesInAction = phases;
}


void SymbianStatusUpdater::reset()
{
    m_currentValue = 0;
    m_logSize = 0;
    m_phase = INITIAL;
    m_lastPhase = INITIAL;
    m_statusText = m_generator.getStatusText();
    m_indefinite = false;
    emit updated();
}


int SymbianStatusUpdater::maximumProgress()
{
    return m_maximumValue;
}


int SymbianStatusUpdater::currentProgress()
{
    return m_currentValue;
}


QString SymbianStatusUpdater::statusText()
{
    return m_statusText;
}


int SymbianStatusUpdater::logSize()
{
    return m_logSize;
}


QFileInfo SymbianStatusUpdater::pkgFileInfo()
{
    // Look for the sis file name in the lastlog
    QRegExp rx;
    rx.setPattern(".*Successfully created.*([^ ]+\\.sis).*");
    for (int i = 0;i < LASTLOG_ITEMS; i++)
    {
        if (rx.indexIn(m_lastLog[i]) != -1)
        {
            QFileInfo info(m_generator.generatorData().projectDirectory() + "/" + rx.cap(1));
            if (info.exists())
            {
                return info;
            }
        }
    }
    return QFileInfo();
}


void SymbianStatusUpdater::increase(QString message)
{
    // Set the last log messages to an array
    m_lastLog[m_lastLogCounter] = message;
    m_lastLogCounter = (m_lastLogCounter + 1) % LASTLOG_ITEMS;

    // See if progress is on and status should be updated
    if (m_phasesInAction > 0)
    {
        m_logSize++;
        updateGeneratorStatus(false);
    }
}


void SymbianStatusUpdater::start(GeneratorTarget target)
{
    reset();

    switch (target)
    {
    case PREVIEW:
        m_phasesInAction = 3;
        break;
    case BUILD:
        m_phasesInAction = 9;
        break;
    case REBUILD:
        m_phasesInAction = 8;
        break;
    default:
        m_indefinite = true;
        break;
    }
}


void SymbianStatusUpdater::stop()
{
    updateGeneratorStatus(true);
}


int SymbianStatusUpdater::phaseLength(GeneratorPhase phase)
{
    switch (phase.m_phase)
    {
    case INITIAL:
        return 1;
    case UNZIP_WIDGET:
        return 150;
    case QMAKE_APP:
        return 10;
    case MAKE_APP:
        return 100;
    case MAKESIS_APP:
        return 6;
    case ENDED_SUCCESSFULLY:
        return 1;
    case ENDED_WITH_ERRORS:
        return 1;
    default:
        return 10;
    }
}

